﻿using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.EmotionsPack;
using CoachingOrganizer.Logic.Common;
using CoachingOrganizer.Logic.Logic.Common;
using CoachingOrganizer.Logic.Models.Tools.EmotionsPack;
using CoachingOrganizer.Toolkit.Events;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CoachingOrganizer.Logic.Logic.Tools.EmotionsPack
{
    internal class EmotionsPackLogic : ToolLogicBase
    {
        private readonly EmotionsPackModel _model;
        private readonly IEmotionsPackInfo _localData;
        private readonly List<EmotionTraceItemLogic> _emotionTraceItems = new List<EmotionTraceItemLogic>();
        private readonly List<EmotionTraceLogic> _emotions = new List<EmotionTraceLogic>();

        public EmotionsPackLogic(EmotionsPackModel model, LogicExtender logicExtender, GoalLogic upperLogic, IEmotionsPackInfo localData)
            : base(model, logicExtender, upperLogic, localData)
        {
            _model = model;
            _localData = localData;
            model.EnumerateTraceItemsDelegate = EnumerateTraceItems;
            model.RequestEmotionTraceDelegate = RequestEmotionTrace;
        }

        public ActionResult<EmotionTraceItemLogic> AddNewTraceItem(EmotionTraceLogic traceLogic, string traceItemName, byte[] picture)
        {
            ActionResult<IEmotionTraceItemInfo> emotionTraceItemInfoResult = _localData.AddNewTraceItem(i =>
            {
                i.EmotionName = traceLogic.Model.EmotionName;
                i.TraceItemName = traceItemName;
                i.TracePicture = picture;
            });
            if (!emotionTraceItemInfoResult.IsValid)
                return ActionResult<EmotionTraceItemLogic>.GetErrorResult(emotionTraceItemInfoResult);
            EmotionTraceItemLogic emotionTraceItem = new EmotionTraceItemLogic(new EmotionTraceItemModel
            {
                TraceItemName = traceItemName,
                TracePicture = picture
            }, _logicExtender, traceLogic, emotionTraceItemInfoResult.Result);
            _emotionTraceItems.Add(emotionTraceItem);
            return ActionResult<EmotionTraceItemLogic>.GetValidResult(emotionTraceItem);
        }

        public ActionResult RemoveTraceItem(EmotionTraceItemLogic logicObject)
        {
            ActionResult outResult = logicObject.LocalData.Remove();
            if (outResult.IsValid)
            {
                _emotionTraceItems.Remove(logicObject);
                EmotionTraceLogic emotionTraceLogic = _emotions.FirstOrDefault(e => e.Model.EmotionName == logicObject.EmotionName);
                if (emotionTraceLogic != null)
                    emotionTraceLogic.CommitTraceItemRemove(logicObject);
            }
            return outResult;
        }

        public void NotifyEmotionTraceItemsCollectionChanged(NotifyCollectionChangedEventArgs args)
        {
            _model.NotifyEmotionTraceItemsCollectionChanged(args);
        }

        private ActionResult<IEnumerable<EmotionTraceItemLogic>> EnumerateTraceItems()
        {
            IEnumerable<IEmotionTraceItemInfo> traceItemsInfo = _localData.TraceItemsInfo;
            return ActionResult<IEnumerable<EmotionTraceItemLogic>>.GetValidResult(traceItemsInfo.Select(i => CreateTraceItemLogic(i)));
        }

        private ActionResult<EmotionTraceLogic> RequestEmotionTrace(string emotionName)
        {
            List<EmotionTraceLogic> emotions = _emotions;
            if (emotions == null)
                ActionResult<EmotionTraceLogic>.GetErrorResult(new KeyNotFoundException());
            EmotionTraceLogic outResult = emotions.FirstOrDefault(e => e.Model.EmotionName == emotionName);
            if (outResult == null)
            {
                outResult = new EmotionTraceLogic(new EmotionTraceModel(emotionName), _logicExtender, this);
                _emotions.Add(outResult);
                _model.ModifyEmotionCollection(col => col.Add(outResult.Model));
                outResult.Model.LoadTraceItemsAsync();
            }
            return ActionResult<EmotionTraceLogic>.GetValidResult(outResult);
        }

        private EmotionTraceItemLogic CreateTraceItemLogic(IEmotionTraceItemInfo info)
        {
            EmotionTraceLogic emotionTraceLogic = _emotions.FirstOrDefault(e => e.Model.EmotionName == info.EmotionName) ?? CreateEmotionTraceLogic(info.EmotionName);
            EmotionTraceItemLogic outResult = new EmotionTraceItemLogic(new EmotionTraceItemModel
            {
                TraceItemName = info.TraceItemName,
                TracePicture = info.TracePicture
            }, _logicExtender, emotionTraceLogic, info);
            _emotionTraceItems.Add(outResult);
            emotionTraceLogic.AddTraceItem(outResult);
            return outResult;
        }

        private EmotionTraceLogic CreateEmotionTraceLogic(string emotionName)
        {
            EmotionTraceLogic outResult = new EmotionTraceLogic(new EmotionTraceModel(emotionName), _logicExtender, this);
            _emotions.Add(outResult);
            return outResult;
        }
    }
}
